
var net = require('net');
//var actorify = require('./roleactor.js');
var async = require('async');

var fmt = require('util').format;
var amp = require('amp');
var Message = require('amp-message');
var parse = require('ms');

var MODNAME = 'stackclient';

var slice = [].slice;
/**
 * stacks client object prototype
 *
 * @api private
 */
function StacksClient(pParentObj) {
  var client = {};
  //client._actor = null;
  client._connection = null;
  client._isConnected = false;
  client._queues = {};
  
  MODNAME = pParentObj._modname + '_' + MODNAME;
  client.logger = pParentObj.logger;

  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'new instance is created');

  /**
   * Inspect implementation.
   */

  client.inspect = function(){
   // var cbs = Object.keys(this.callbacks).length;
    return fmt('StacksClient ');
  };

  /**
   * connect to server
   * 
   * @api public
   * @param <Mixed> server
   * @param <Function> callback
   */
  client.connect = function connect(server, callback) {
	 
	  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'connecting server...');

	  client._connection = net.connect(server, function() {
  	  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'connected to server successfully...');
    
  	  
  	  client.parser = new amp.Stream;
  	  client.parser.on('data', client.onMessage.bind(client));    
  	  client._connection.pipe(client.parser);
      	  
  	  //client._actor = actorify(client._connection);

      /**
       * handle stacks request of type |type| with worker |worker|
       * allow |concurrency| concurrent workers
       *
       * @api public
       * @param <String> type
       * @param <Function> worker
       * @param <Number> concurrency
       */
      client.on = function on(type, worker, concurrency) {    	      	  
    	  client._queues[type] = async.queue(worker, concurrency);
    	  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'created asynchronus queue for requests of type: '+ type);
      };

      /**
       * debug messages for socket events
       */
     
      client._connection.on('end', function() {
    	  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'socket end...');
      });
      client._connection.on('close', function() {
    	  client.logger.log(MODNAME, 'INFO_LEVEL_4', 'socket closed...');
      });     
      
      client._isConnected = true;
      callback(null, client);
    });
    
    client._connection.on('error', function(error) {
    client.logger.log(MODNAME, 'INFO_LEVEL_4', 'socket error: ' + error.message);
    callback(error, null);
    });
    client._connection.on('timeout', function() {
    	client.logger.log(MODNAME, 'INFO_LEVEL_4', 'socket timeout...');
        var error = new Error();
//    	console.log("Error :" + err.stack);
//    	console.log("Error :" + err.lineNumber);
        error.message = 'Connection request timeout';
        callback(error, null);

      });
  };

  /**
   * disconnect stacks client
   *
   * @api public
   */
  client.disconnect = function disconnect() {

	client.logger.log(MODNAME, 'INFO_LEVEL_4', 'disconecting...');
	client._connection.end();
	client.removeClient();
  };
  
  client.onMessage = function (buf) {
	var self = client;
	var msg = new Message(buf);

	client.logger.log(MODNAME, 'INFO_LEVEL_4', 'onMessage() Received: ' + JSON.stringify(msg.args));
	var args = msg.args;

	var msgId = args.shift();
	var msgType = args.shift();
	var msgBody = args.shift();
	var replyFunc = function(){ // arguments = err, eventbody
		self.send.apply(self, reply(msgId, arguments));
	};
	//add to queue for dispatch
	var msgInfo = {
	id: msgId,
	type: msgType,
	body: msgBody,
	reply: replyFunc
	};

    client._queues[msgType].push(msgInfo);
  };
  
  client.send = function () {
	if ('string' != typeof arguments[0]) throw new Error('missing message name');
	var args = slice.call(arguments);
	 
	var msg = new Message(args);
	client._connection.write(msg.toBuffer());
	client.logger.log(MODNAME, 'INFO_LEVEL_4', 'send() Sent message: '+JSON.stringify(msg.args));
  };

  /**
   * expose public api
   */
  this.connect = client.connect;
  this.disconnect = client.disconnect;
}

function reply(id, args) {
	var msg = new Array(2 + args.length);

	msg[0] = '_reply_';
	msg[1] = id;

	for (var i = 0; i < args.length; i++) {
		msg[i + 2] = args[i];
	}

	return msg;
}

module.exports = StacksClient;